﻿#region File and License Information
/*
<File>
	<Copyright>Copyright © 2009, Daniel Vaughan. All rights reserved.</Copyright>
	<License>
	This file is part of DanielVaughan's core library

    DanielVaughan's core library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DanielVaughan's core library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with DanielVaughan's core library.  If not, see http://www.gnu.org/licenses/.
	</License>
	<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
	<CreationDate>2010-02-02 13:55:32Z</CreationDate>
</File>
*/
#endregion

using System;
using System.IO;
using System.Windows.Controls;
using System.Windows.Threading;

using DanielVaughan.ComponentModel;
using DanielVaughan.Data;
using DanielVaughan.IO;
using DanielVaughan.Resources;

namespace DanielVaughan.Services.FileService
{
	public class FileService : IFileService
	{
//		public FileOperationResult SaveAs(string fileName, SaveFileOperationHandler operationHandler,
//			FileErrorAction fileErrorAction)
//		{
//			return SaveAs(fileName, operationHandler, fileErrorAction, null, null, null);
//		}

		public FileOperationResult SaveAs(SaveFileOperationHandler operationHandler,
			FileErrorAction fileErrorAction, SaveFileSelectionArgs fileSelectionArgs)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");

			//var shell = ServiceLocatorSingleton.Instance.GetInstance<IMainWindow>() as Window;
			var dialog = new SaveFileDialog();
			if (fileSelectionArgs != null)
			{
				if (!string.IsNullOrEmpty(fileSelectionArgs.FileExtension))
				{
					dialog.DefaultExt = fileSelectionArgs.FileExtension;
				}
				if (fileSelectionArgs.FilterCount > 0)
				{
					dialog.Filter = fileSelectionArgs.FilterString;
				}
				if (fileSelectionArgs.FilterIndex.HasValue)
				{
					dialog.FilterIndex = fileSelectionArgs.FilterIndex.Value;
				}
			}
			/* TODO: Customize the save dialog. */
			//dialog.FileName = fileName;
			if (!dialog.ShowDialog().Value)
			{
				return FileOperationResult.Cancelled;
			}

			return Save(dialog.SafeFileName, operationHandler, fileErrorAction, dialog.OpenFile, fileSelectionArgs);
		}

		public FileOperationResult Save(SaveFileOperationHandler operationHandler, FileErrorAction fileErrorAction, Func<Stream> getStreamFunc)
		{
			throw new NotImplementedException();
		}

		FileOperationResult Save(string fileName, SaveFileOperationHandler operationHandler, 
			FileErrorAction fileErrorAction, Func<Stream> getStreamFunc, SaveFileSelectionArgs fileSelectionArgs)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");

			FileErrorAction actualFileErrorAction = fileErrorAction;

			string userMessage = null;
			bool ioExceptionOccured = false;
			try
			{
				operationHandler(fileName, getStreamFunc);		
				return FileOperationResult.Successful;
			}
			catch (IOException ex)
			{
				//log.Info("Unable to save file: " + fileName, ex);
				userMessage = "A problem occured saving the file."; /* TODO: Make localizable resource. */
				ioExceptionOccured = true;
			}
			catch (Exception ex) /* TODO: catch common IO errors and report to user. */
			{
				//log.Info("Unable to save file: " + fileName, ex);
				var userMessageException = ex as IUserMessageProvider;
				if (userMessageException != null && userMessageException.UserMessagePresent)
				{
					userMessage = userMessageException.UserMessage;
				}
			}

			if (!ioExceptionOccured)
			{
				if (fileErrorAction == FileErrorAction.UseAlternative)
				{	/* If this wasn't an IOException then we do not allow the user to select an alternative. */
					actualFileErrorAction = FileErrorAction.InformOnly;
				}
			}

			var result = FileOperationResult.Failed;

			var messageService = ServiceLocatorSingleton.Instance.GetInstance<IMessageService>();

			switch (actualFileErrorAction)
			{
				case FileErrorAction.UseAlternative:
					messageService.ShowError(userMessage, StringResources.Services_FileService_UnableToSaveFile);
					do
					{
						result = SaveAs(operationHandler, FileErrorAction.InformOnly, fileSelectionArgs);
					} while (result != FileOperationResult.Successful && result != FileOperationResult.Cancelled);
					break;
				case FileErrorAction.InformOnly:
					messageService.ShowError(userMessage, StringResources.Services_FileService_UnableToSaveFile);
					break;
			}
			return result;
		}

		public FileOperationResult Open(FileOperationHandler operationHandler,
			FileErrorAction fileErrorAction, OpenFileSelectionArgs openFileSelectionArgs)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");
			return Open(null, operationHandler, fileErrorAction, openFileSelectionArgs);
		}

		public FileOperationResult Open(MultiFileOperationHandler operationHandler, 
			FileErrorAction fileErrorAction, OpenFileSelectionArgs fileSelectionArgs)
		{
			throw new NotImplementedException();
		}

		public FileOperationResult Open(string filePath, FileOperationHandler operationHandler,
			FileErrorAction fileErrorAction, OpenFileSelectionArgs fileSelectionArgs)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");

			string fileNameToUse = filePath;
			FileInfo fileInfo = null;
			FileOperationResult result = FileOperationResult.Successful;
				
			var dispatcher = ServiceLocatorSingleton.Instance.GetInstance<Dispatcher>();
			dispatcher.InvokeIfRequired(delegate
			{
				var dialog = new OpenFileDialog();
				/* TODO: Customize the save dialog. */
				//dialog.Title = "Choose file name";
				if (fileSelectionArgs != null)
				{
					fileSelectionArgs.SetDialogProperties(dialog);
				}

				if (!dialog.ShowDialog().Value)
				{
					result = FileOperationResult.Cancelled;
					return;
				}
				fileInfo = dialog.File;
			});

			if (result != FileOperationResult.Successful)
			{
				return result;
			}

			string userMessage = null;
			try
			{
				operationHandler(fileInfo);
				return FileOperationResult.Successful;
			}
			catch (MementoIncompatibilityException ex)
			{
				userMessage = string.Format(StringResources.Services_FileService_FileCreatedInNewerVersion, fileNameToUse);
				//log.Info("Unable to open file: " + filePath, ex);
			}
			catch (Exception ex) /* TODO: catch common IO errors and report to user. */
			{
				//log.Info("Unable to open file: " + filePath, ex);
			}

			if (userMessage == null)
			{
				userMessage = string.Format(StringResources.Services_FileService_UnableToOpenFile, fileNameToUse);
			}

			var messageService = ServiceLocatorSingleton.Instance.GetInstance<IMessageService>();

			switch (fileErrorAction)
			{
				case FileErrorAction.UseAlternative:
					messageService.ShowWarning(userMessage);
					result = Open(null, operationHandler, FileErrorAction.UseAlternative, fileSelectionArgs);
					return result;
				case FileErrorAction.InformOnly:
					messageService.ShowWarning(userMessage);
					break;
			}
			return FileOperationResult.Failed;
		}
	}
}
